我相信很多人在使用Arduion的時候還是不清楚PWM到底在幹嘛?
PWM是一種可以將類比訊號以數位編碼來表示的技術,而表示的方法就是利用高頻率的方波,並時時的改變工作週期(duty cycle),達到模擬類比訊號的效果。
為什麼這樣的波形就可以模擬類比訊號的輸出呢?
我們可以用LED來想像,如果波的頻率很慢,例如1秒高電位1秒低電位,那我們肉眼就會看到燈泡閃爍,那如果頻率超級高呢?例如頻率是1MHz,也就是1秒鐘高低電位變化一百萬次,這已經遠遠的超出肉眼可以辨識的頻率了,此時你就會看到LED的亮度變一半。我們可以調整一個周期內高電位的比率(這也就是duty cycle),如果在一個周期內有90%的時間都是高電位的話,那自然燈泡的亮度就會比較亮。
有兩個參數,第一個就是頻率,另一個就是工作週期(duty cycle)。假設一個PWM的頻率是1kHz、工作週期為30%,那也就是一個波的週期是1ms,而在這一毫秒當中,有0.3ms是高電位。
Arduino的analogWrite輸出的就是方波,而他預設的頻率為490Hz不太能更動,而我們函式放的參數是0~255,這竟是調整工作週期,255時,工作週期為100%
我們首先打開TIM2、CH1的PWM Output,選哪一個channel都沒關係,只是不同channel會對應到不同的腳位(TIM2 CH1的腳位是PA0),一樣可以在底下configuration的GPIO setting裡面找到。
方波的輸出是利用timer,我們需要調整三個參數,PSC、ARR、與Pulse,這些參數與timer的使用相同,只有pulse是新的,在預設情形下CNT < Pulse的情況會是輸出高電位,反之則輸出低電位。
我們首先產生一個頻率為1kHz,dutycycle為50%的方波。三個參數的配置如下:
PSC = 15
ARR = 1000
Pulse = 500
=>duty cycle = 500 / 1000 * 100% = 50%
只需要一個函式就可以了!
HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
把它放在while迴圈之前啟動一次即可,第二個參數放你要啟用哪一個頻道,可以為TIM_CHANNEL_1~4,如果要一次啟用多個也可以放TIM_CHANNEL_ALL。
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
但是問題來了,你要如何知道你有正確輸出呢?
有兩種方式,一種是你直接拿電錶測量,但這種方式你只會測量到平均出來的電壓,一般GPIO的輸出是3.3V,而我們設定的duty cycle = 50% 因此用電表量出來的電壓應為3.3 * 0.5 = 1.65V。但是這種方式並不是很值觀的看到我們的輸出,也有可能它本身的輸出就是1.65V啊。因此這時候我們就需要使用示波器,這真的可以說是一個很好用的工具,重要性不亞於三用電表。他也是我們debug的好工具。
在這裡我們就不教學示波器的操作了,它的用法其實與三用電表很相似,只是它測量的頻率非常高,並在螢幕上顯示波形。底下是用示波器看到PA0這個腳位輸出的波形,可以看到頻率為1.005kHz,工作週期為49.93%與我們設定的值相當接近。
接下來還有一個問題,我們都知道伺服馬達是透過不同的工作週期來調整角度,那我們要控制角度也就是要調整工作週期,因此我們要有辦法更改pulse的值。
__HAL_TIM_SET_AUTORELOAD(__HANDLE__, __AUTORELOAD__)
__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
第一個函式可以改ARR的值,第二個函式可以修改Pulse的值。這裡要注意的是,同一個timer,的ARR值是相同的,也就是說同一個timer,不同頻道所產生的方波,頻率皆相同。而Pulse則是每個頻道獨立的,因此我們可以再同一個timer中不同頻道產生出不同工作週期的方波。
例如我們要修改TIM2的ARR值為50可以寫成:
__HAL_TIM_SET_AUTORELOAD(&htim2, 50);
而我們要修改TIM2的Channel 1的Pulse為50可以寫成:
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,50);
學會這個功能之後,相當於解鎖了新的領域,我們可以用來控制伺服馬達、步進馬達...,PWM的輸出難度不大,只要稍微計算一下工作週期ARR、PSC、Pulse,來符合我們要的頻率與工作週期即可。明天我們就來實際控制Servo!